﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.OleDb;
using System.Data.Odbc;
using System.Data.SqlClient;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Collections;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.Net;
using System.Collections.Specialized;
using System.Configuration;
using System.Xml;
namespace ContentMigrator
{
    public partial class frmMetabaseImport : Form
    {

        private SPWeb moCurrentWeb;
        private SPList moCurrentLib;
        private SPWeb moRootWeb;
        private Hashtable htChoiceFieldValues = new Hashtable();
        private DataView mdv = null;
        private string XMLFile = string.Empty;
        private bool mbAllowUserAdd;

        public frmMetabaseImport()
        {
            InitializeComponent();
        }

        private DataView XMLToDataView(string xmlfile) {
            try
            {
                
                XmlDocument doc = new XmlDocument();
                doc.Load(xmlfile);
                XmlNodeList items = doc.SelectNodes("Data/Item");

                //create a data table based on attributes
                DataTable table = new DataTable("Content");
                XmlNode first = items[0];
                foreach (XmlAttribute attrib in first.Attributes)
                {
                    table.Columns.Add(attrib.Name);
                }

                //add rows to the table
                foreach (XmlNode item in items)
                {
                    string[] values = new String[item.Attributes.Count];
                    int index = 0;
                    foreach (XmlAttribute attrib in item.Attributes)
                    {
                        values[index] = attrib.Value;
                        index++;
                    } 
                    DataRow row = table.Rows.Add(values);
                }

                DataView dv = new DataView(table);
                return dv;

            }
            catch (Exception ex)
            {
                
                throw new Exception("XMLToDataView: " + ex.Message);
            }
        }
        private DataView GetData(string xmlfile)
        {
            try
            {
                if (mdv == null)
                    mdv = XMLToDataView(xmlfile);

                return mdv;
            }
            catch (Exception ex)
            {
                
                throw new Exception("GetData: " + ex.Message);
            }
        }

        private void EnumFolders(SPList mylib)
        {
            try
            {
                StaticMethods.EnumFoldersToComboBox(mylib, cbxFolder);

                //add FolderTree field from metabase
                cbxFolder.Items.Add("@FolderTree");

            }
            catch (Exception)
            {

                throw;
            }
        }

      
        private void frmMetabaseImport_Load(object sender, EventArgs e)
        {
            try
            {
                moRootWeb = StaticMethods.GetWebFromUrl(new Uri(Properties.Settings.Default.RootWeb));
                StaticMethods.EnumSitesToComboBox(moRootWeb, cbxSite);
                StaticMethods.EnumLibrariesToComboBox(moCurrentWeb, cbxLibrary);
                StaticMethods.EnumFoldersToComboBox(moCurrentLib, cbxFolder);
            }
            catch (Exception ex)
            {
                throw new Exception("Startup error:" + ex.Message);
                this.Close();
            }
        }
        private void EnumContentTypes(SPList mylib)
        {
            StaticMethods.EnumContentTypesToComboBox(mylib, cbxContentTypes);

            if (cbxContentTypes.Items.Count == 0)
            {
                dgvMetadata.DataSource = null;
                dgvMetadata.Refresh();
            }

            lblContentTypes.Enabled = (cbxContentTypes.Items.Count > 0);
            cbxContentTypes.Enabled = (cbxContentTypes.Items.Count > 0);
            btnUpload.Enabled = (cbxContentTypes.Items.Count > 0);
        }

        private void cbxSite_SelectedIndexChanged(object sender, EventArgs e)
        {
            moCurrentWeb = StaticMethods.GetWebFromUrl(new Uri(cbxSite.Text));
            StaticMethods.EnumLibrariesToComboBox(moCurrentWeb, cbxLibrary);
        }
        private void cbxLibrary_SelectedIndexChanged(object sender, EventArgs e)
        {
            moCurrentLib = moCurrentWeb.Lists[cbxLibrary.Text];
            EnumContentTypes(moCurrentLib);
            EnumFolders(moCurrentLib);
        }


        private void btnUpload_Click(object sender, EventArgs e)
        {
            try
            {
                string path = string.Empty;
                StringBuilder Report = new StringBuilder();
#if DEBUG
                StringBuilder Log = new StringBuilder();
#endif
                string metacol = string.Empty;
                SPFolder folder = null;

                Cursor.Current = Cursors.WaitCursor;
                this.Enabled = false;
                progressBar1.Visible = true;
                progressBar1.Value = 0;
                progressBar1.Maximum = mdv.Count;

                // Upload each file with the specified metadata information
                GetData(XMLFile);
                foreach (DataRow item in mdv.Table.Rows)
                {
                    try
                    {
#if DEBUG
                        Log.AppendLine("Top of main loop");
#endif
                        Hashtable properties = new Hashtable();

                        // Only properties that have been filled in will be added to the new file
                        //foreach (DataRow row in dtMetadata.Rows)
#if DEBUG
                        Log.AppendLine("Before metadata loop");
#endif
                        for (int i = 1; i < dgvMetadata.Rows.Count; i++)
                        {
#if DEBUG
                            Log.AppendLine("Top of metadata loop");
#endif
                            DataGridViewRow row = dgvMetadata.Rows[i];
#if DEBUG
                            Log.AppendLine("row set");
#endif
                            string key = row.Cells["Key"].Value.ToString();
                            if (!StaticMethods.ValidateFieldValue(moCurrentLib, cbxContentTypes.Text, key, row.Cells["Value"].Value))
                            {
                                throw new Exception("Invalid value specified for field " + key + ".");
                            }

                            if (row.Cells["Value"].Value != null)
                            {
#if DEBUG
                                Log.AppendLine("Metadata value not empty:" + row.Cells["Value"].Value.ToString());
#endif
                                if (row.Cells["Value"].Value.ToString().StartsWith("@"))
                                {
#if DEBUG
                                    Log.AppendLine("Use metabase column");
#endif
                                    //use a column from content metabase as the value
                                    metacol = row.Cells["Value"].Value.ToString().Replace("@", "");
#if DEBUG
                                    Log.AppendLine("metacol set");
#endif

                                    //is it a valid column name?
                                    if (mdv.Table.Columns.Contains(metacol))
                                    {
                                        properties.Add(row.Cells["Key"].Value.ToString(), item[metacol].ToString());
#if DEBUG
                                        Log.AppendLine("Value added to hashtable");
#endif
                                    }
                                    else
                                    {
                                        throw new Exception("'" + metacol + "' is not a valid metabase column!");
                                    }
                                }
                                else
                                {
                                    //literal value
                                    properties.Add(row.Cells["Key"].Value.ToString(), row.Cells["Value"].Value.ToString());
                                }
                            }
                        }
#if DEBUG
                        Log.AppendLine("After metadata loop");
#endif

                        if (item["filename"] != null)
                        {
                            path = item["Filename"].ToString();

                            string filename = string.Empty;
                            byte[] fileContents = StaticMethods.GetFileBytes(path);
#if DEBUG
                            Log.AppendLine("File bytes retrieved: " + fileContents.Length.ToString());
#endif

                            if (path.ToLower().Contains("http") || path.ToLower().Contains("ftp"))
                                filename = path.Substring(path.LastIndexOf("/") + 1);
                            else
                                filename = path.Substring(path.LastIndexOf("\\") + 1);

                            
                            //retrieve or create destination folder
                            if (cbxFolder.Text.ToLower() == "<root>")
                            {
                                //use root folder of library
                                folder = moCurrentWeb.GetFolder(moCurrentLib.RootFolder.Url);
#if DEBUG
                                Log.AppendLine("Root folder retrieved");
#endif
                            }
                            else if (cbxFolder.Text.ToUpper() == "@FOLDERTREE")
                            {
                                //get folder structure from metabase field
                                folder = StaticMethods.GetFolderTree(moCurrentWeb, moCurrentLib, item["FolderTree"].ToString(), chkCreateFolder.Checked);
#if DEBUG
                                Log.AppendLine("Folder tree retrieved/created");
#endif
                            }
                            else
                            {
                                //existing subfolder
                                folder = moCurrentWeb.GetFolder(moCurrentLib.RootFolder.ServerRelativeUrl + "/" + cbxFolder.Text);
#if DEBUG
                                Log.AppendLine("Literal folder retrieved");
#endif
                                //folder = moCurrentWeb.GetFolder(moCurrentLib.Folders[cbxFolder.SelectedIndex - 1].Url);
                                if (!folder.Exists)
                                    throw new Exception("Could not connect to folder '" + cbxFolder.SelectedText + "'");
                            }

                            //clean filename
                            filename = StaticMethods.CleanFilename(filename);

                            //add file to library
                            SPFile myfile = folder.Files.Add(filename, fileContents, chkOverwrite.Checked);

                            
                            if (!myfile.Exists)
                                throw new Exception("File not added to folder");
#if DEBUG
                            Log.AppendLine("File added to folder");
                            Log.AppendLine("Setting metadata fields as follows:");
#endif
                            //fill metadata fields
                            foreach (string mykey in properties.Keys)
                            {
#if DEBUG
                                Log.AppendLine(mykey + "=" + properties[mykey].ToString());
#endif
                                string val = properties[mykey].ToString();
                                if (mykey == "FileLeafRef")
                                {
                                    val = StaticMethods.CleanFilename(val);
                                }
                                myfile.Item[mykey] = val;
                            }
                            //update fields
                            myfile.Item.Update();

#if DEBUG
                            Log.AppendLine("File metadata fields updated");
#endif
                        }
                    }
                    catch (Exception ex)
                    {
                        Report.AppendLine(path + "\t" + ex.Message);
#if DEBUG
                        string logfile = System.Environment.CurrentDirectory + "\\ImportLog_" + DateTime.Now.ToString("MMddyyhhmmss") + ".txt";
                        if (File.Exists(logfile) == true)
                        {
                            File.Delete(logfile);
                        }
                        File.WriteAllText(logfile, Log.ToString());
                        string errfile = StaticMethods.WriteErrFile(Report);
                        MessageBox.Show("DEBUG BUILD: Fatal error. Check the log file " + logfile + " and error file " + errfile + ".\r\nApplication will now terminate.", "DEBUG: ERROR", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        this.Close();
#endif
                    }
                    progressBar1.Value += 1;
                    progressBar1.Refresh();
                    Application.DoEvents();
                }

                progressBar1.Visible = false;
                Cursor.Current = Cursors.Default;
                this.Enabled = true;

                if (Report.ToString() != string.Empty)
                {
                    string errfile = StaticMethods.WriteErrFile(Report);
                    MessageBox.Show("Completed with errors:\r\nSee error file " + errfile + " for details.", "COMPLETED WITH ERRORS", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
                else
                    MessageBox.Show("Completed.", "COMPLETED", MessageBoxButtons.OK, MessageBoxIcon.Information);

            }
            catch (Exception ex)
            {
                Cursor.Current = Cursors.Default;
                this.Enabled = true;
                progressBar1.Visible = false;
                MessageBox.Show(ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }


        private void cbxContentTypes_SelectedIndexChanged(object sender, EventArgs e)
        {

           StaticMethods.EnumContentTypeFieldsToDataGridView(moCurrentLib, cbxContentTypes.Text, dgvMetadata, htChoiceFieldValues);
            btnUpload.Enabled = (dgvMetadata.Rows.Count > 0);

        }
        void dgvMetadata_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
        }

        void dgvMetadata_CellEnter(object sender, DataGridViewCellEventArgs e)
        {

        }
        void BindComboToArrayList(ComboBox mycombo, ArrayList myarray)
        {
            try
            {
                mycombo.Items.Clear();
                foreach (string myval in myarray)
                {
                    mycombo.Items.Add(myval);
                }
            }
            catch (Exception ex)
            {

                throw new Exception("BindComboToArrayList:" + ex.Message);
            }
        }
        void dgvMetadata_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        {
            try
            {
                if (e.Control.GetType() == typeof(DataGridViewComboBoxEditingControl))
                {
                    //get reference to editing control
                    DataGridViewComboBoxEditingControl cbo = e.Control as DataGridViewComboBoxEditingControl;

                    string metacol = dgvMetadata.Rows[dgvMetadata.CurrentRow.Index].Cells["Key"].Value.ToString();
                    System.Diagnostics.Debug.WriteLine(dgvMetadata.CurrentRow.Index);
                    System.Diagnostics.Debug.WriteLine(metacol);
                    if (htChoiceFieldValues.Contains(metacol))
                    {
                        StaticMethods.SetupGridDropdownColumn((ArrayList)htChoiceFieldValues[metacol], cbo, true);
                        if (mdv != null)
                            StaticMethods.SetupGridDropdownColumn(mdv.Table.Columns, cbo, false);
 
                        //do not allow user to add their own value
                        cbo.DropDownStyle = ComboBoxStyle.DropDownList;
                        mbAllowUserAdd = false;
                        cbo.Validating += new CancelEventHandler(cbo_Validating);
                    }
                    else
                    {
                        if (mdv != null)
                            StaticMethods.SetupGridDropdownColumn(mdv.Table.Columns, cbo,true);
                        
                        //allow user to add their own value
                        cbo.DropDownStyle = ComboBoxStyle.DropDown;
                        mbAllowUserAdd = true;
                        cbo.Validating += new CancelEventHandler(cbo_Validating);
                    }
                }
            }
            catch (Exception ex)
            {

                throw new Exception("dgvMetadata_EditingControlShowing:" + ex.Message);
            }

        }
        void cbo_Validating(object sender, CancelEventArgs e)
        {

            try
            {
                DataGridViewComboBoxEditingControl cbo = sender as DataGridViewComboBoxEditingControl;

                DataGridView grid = cbo.EditingControlDataGridView;
                DataGridViewComboBoxColumn cboCol = grid.Columns[grid.CurrentCell.ColumnIndex] as DataGridViewComboBoxColumn;
                object value = cbo.Text;


                if (mbAllowUserAdd)
                {
                    // Add value to list if not there


                    if (cbo.Items.IndexOf(value) == -1)
                    {



                        // Must add to both the current combobox as well as the template, to avoid duplicate entries...


                        cbo.Items.Add(value);


                    }
                }
                grid.CurrentCell.Value = value;
                cboCol.Items.Add(value);
            }
            catch (Exception)
            {

            }


        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            OpenFileDialog fd = new OpenFileDialog();
            fd.Filter = "XML Files|*.xml";
            fd.InitialDirectory = "C:\\";
            fd.ShowDialog();

            lblDisplay.Text = fd.FileName;
            XMLFile = fd.FileName;
            if (XMLFile != string.Empty)
            {
                GetData(XMLFile);
            }
        }
    }
}
